iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 15
2
Modern Web

I Want To Know React系列 第 15 篇

I Want To Know React - 條件 render

  • 分享至 

  • xImage
  •  

React 條件 render

使用情境

在撰寫前端頁面時,常常需要根據不同的 props / state 資料顯示不同的 element。

舉例來說,使用者尚未登入的話要顯示登入按鈕;使用者已經登入的話則顯示登出按鈕。

在這章節中,我們就要來學習如何根據不同的條件 render 出對應的 element。

實作概念

條件 render 其實沒有任何特殊的語法,它只是 JavaScript 與 JSX 的應用而已。任何 if else expression / statement 的條件判斷方式都可以用來條件 render。

如初探 Component & Props 篇所講,回傳 React element 的 function 就是一個合法的 component,而 component 內要執行哪些邏輯後才回傳 React element 則是開發者可以自由發揮的實作細節。

只要熟悉初探 JSX 與 JSX 語法章節的內容,相信讀者一定能快速掌握條件 render 的精髓。

以下將說明 React 條件 render 的使用方式與常見技巧。這些方法都是可行的條件 Render 處理方式,讀者視可讀性與當下情境應用、延伸、選擇要使用的寫法。

技巧:if else 判斷要 render 的 component

第一種方法是透過 JavaScript 的 if else 選擇要 render 哪個 element。

承開頭所說的例子。假設我們有一個網頁:

  • 使用者尚未登入的話要顯示登入按鈕
  • 使用者已經登入的話則顯示登出按鈕

則可以這樣實作:

function LoginButton(props) {
	return <button>Login</button>;
}

function LogoutButton(props) {
	return <button>Logout</button>;
}

function LoginStatusPanel(props) {
	if (props.isLoggedIn) {
    return <LogoutButton/>;
  }
	return <LoginButton/>;
}

ReactDOM.render(
  <LoginStatusPanel isLoggedIn={false} />,
  document.getElementById('root')
);

可以看到這個範例只是根據不同的情境返回不同的 React element 而已。條件 render 內容如下:

  • 如果帶入 LoginStatusPanel 的 props 內容為 isLoggedIn === true 的話就回傳 <LogoutButton /> React element
  • 如果 LoginStatusPanel 的 props 內容為 isLoggedIn === false 的話則回傳 <LoginButton /> React element

技巧:用變數儲存要顯示的 element

第二種方式是把要 render 的 element 判斷好後存在變數中,並在 JSX Expression 中使用這個變數。

讓我們換個做法實作 LoginStatusPanel:

function LoginButton(props) {
	return <button>Login</button>;
}

function LogoutButton(props) {
	return <button>Logout</button>;
}

function LoginStatusPanel(props) {
  const button = props.isLoggedIn ? <LogoutButton/> : <LoginButton/>
	return (
    <div>
      <h1>Login panel</h1>
      {button}
    </div>
  );
}

範例中,<LoginButton /> 與 <LogoutButton /> 會根據 props.isLoggedIn 的值判斷完後存到 button 變數中。

  • 如果 isLoggedIn 則 button 內容為 <LogoutButton />
  • 如果尚未 isLoggedIn 則 button 內容為 <LoginButton />

接著在 <div> 中就可以使用 expression:{button} 將判斷好的 element render 到畫面上。

技巧:用 ?: 決定 render 哪個 element

另外一個方法是直接在 JSX expression 中使用 JavaScript 的三元運算子:?:來決定要 render 哪個 element。

三元運算子的用法如下:

condition ? exp1 : exp2
  • 如果 condition 為 truthy 的話,回傳 exp1 的值
  • 如果 condition 為 falsy 的話,則回傳 exp2 的值

就來用 ?: 改寫 LoginStatusPanel 範例吧:

function LoginButton(props) {
	return <button>Login</button>;
}

function LogoutButton(props) {
	return <button>Logout</button>;
}

function LoginStatusPanel(props) {
	return (
    <div>
      <h1>Login panel</h1>
      { props.isLoggedIn ? <LogoutButton/> : <LoginButton/> }
    </div>
  );
}

可以看到在 LoginStatusPanel 裡的 expression 中,我們用三元式 ?: 做為條件判斷選擇要 render 哪個 element。

  • 如果 isLoggedIn 加入 <LogoutButton /> 到 element 中
  • 如果尚未 isLoggedIn 則加入 <LoginButton /> 到 element 中

技巧:用 && 決定是否 render element

在一些需求下需要讓 component 符合條件就顯示特定 element,而不符合條件就不顯示。我們可以用 expression 中使用 JavaScript 的 && 運算子來達成這件事。

&& 運算子的用法如下:

exp1 && exp2
  • 如果 exp1 為 truthy 的話,回傳 exp2 的值
  • 如果 exp1 為 falsy 的話,則回傳 exp1 的值

讓我們來實際演練吧!

現在要實作一個電子郵件 component Mailbox:

  • 如果有未讀信件的話,要顯示未讀提示
  • 沒有未讀信件的話就不顯示提示

則可以這樣實作:

function Mailbox(props) {
	const unreadMessages = props.unreadMessages;
	return (<div>
		<h1>Hello</h1>
		{unreadMessages.length > 0 &&
			<h2>You have {unreadMessages.length} unread messages</h2>
		}
  </div>);
}

範例中:

  • 如果 unreadMessages.length > 0(代表有未讀信件),會顯示 You have xxx unread messages
  • 如果 unreadMessages.length <= 0(沒未讀信件),則不會出現任何提示,因為 React 收到 false 就會忽略不 render

讓 component 不 render element

在一些特定的情形下,我們會希望 component 在條件判斷不成立的時候不要 render 任何 element。

在 React 中,只要讓 component 回傳以下其中一種值即可不 render 任何 element:

  • 回傳 null
  • 回傳 false

回傳 null 以不 render element

只要 component 回傳 null,React 就不會幫該 component render 任何內容。

舉例來說,如果要實作一個網路斷線提示條:NetworkDisconnectedBar,只在網路斷線的時候顯示。

我們可以用 if 判斷式的方式讓 component 在有網路的狀況下回傳 null 以不顯示任何東西:

function NetworkDisconnectedBar(props) {
	if (props.hasNetwork) return null;

	return <div>Network disconnected</div>;
}

ReactDOM.render(
  <NetworkDisconnectedBar hasNetwork />,
  document.getElementById('root')
);

讀者可以到 CodePen 查看結果。

可以看到範例中,因為 props.hasNetwork 為 true(如果 attribute 沒有 value 的話,其 value 預設值為 true),使 NetworkDisconnectedBar 回傳 null,所以畫面不會為 NetworkDisconnectedBar 顯示任何 element。

回傳 false 以不 render element

同樣的,如果 component 回傳 false,React 也不會幫該 component render 任何內容。

延續剛剛的 NetworkDisconnectedBar 範例,我們可以應用上面段落學到的 && 運算子改寫剛剛的程式,讓 component 在有網路的狀況下回傳 false 以不顯示任何東西:

function NetworkDisconnectedBar(props) {
  return !props.hasNetwork && <div>Network disconnected</div>;
}

ReactDOM.render(
  <NetworkDisconnectedBar hasNetwork />,
  document.getElementById('root')
);

讀者可以到 CodePen 查看範例。

可以看到範例中,同樣的,因為 props.hasNetwork 為 true,使 NetworkDisconnectedBar 回傳 false,所以畫面不會為 NetworkDisconnectedBar 顯示任何 element。

常見錯誤:if else 寫在 JSX Expression 中

當筆者剛開始寫 JSX 條件 render 時常常會寫出錯誤的語法:把 if else 寫在 JSX expression 中。

if else 不能夠直接寫在 JSX expression 中,因為 if else 是 statement,而非 expression。

讓我們來做一次錯誤示範:

function LoginButton(props) {
	return <button>Login</button>;
}

function LogoutButton(props) {
	return <button>Logout</button>;
}

function LoginStatusPanel(props) {
	return (
    <div>
      <h1>Login panel</h1>
			{
				// Parsing error: Unexpected token if
				if (props.isLoggedIn) {
					return <LogoutButton/>;
				} else {
					return <LoginButton/>;
				}
			}
    </div>
  );
}

可以看到 expression 中一寫 if,就會跳出 Parsing error: Unexpected token if 的錯誤。

  • ?小提醒:如何判斷一段程式碼是否為 expression

    只要一段程式碼可以被當作參數傳進 function 即代表它是 expression,因為 function 的參數只接受 expression。

    如果想要更深入了解 JSX 語法與 expression 的讀者,可以閱讀 JSX 語法篇。

小結

React 中,條件 render 其實就只是 JavaScript 的 if else 與 JSX expression 的應用而已。在本章節中,介紹了一些技巧來做到 React 條件 render 的功能,包括:

  • if else 判斷要 render 的 component
  • 用變數儲存要顯示的 element
  • 用 ?: 決定 render 哪個 element
  • 用 && 決定是否 render element

這些技巧都是可行的 JSX 條件 Render 處理方式,讀者應視情況應用、延伸、選擇要使用的寫法。

另外我們也學習到了讓 component 不 render 的技巧:

  • 讓 component 回傳 null
  • 讓 component 回傳 false

最後,我們需要避免錯誤的把 if else 寫在 JSX expression 中,因為 if else 是 statement,非 expression,因此 JSX expression 不接受這種寫法。

參考資料


上一篇
I Want To Know React - 正確使用 Event handler
下一篇
I Want To Know React - Render list
系列文
I Want To Know React 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言